package org.onejava.core.aop;

import java.lang.reflect.Method;
import java.util.List;

import org.onejava.core.aop.inter.IAfter;
import org.onejava.core.aop.inter.IAfterReturn;
import org.onejava.core.aop.inter.IAfterThrowing;
import org.onejava.core.aop.inter.IBefore;
import org.onejava.core.bean.AopEntity;
import org.onejava.core.bean.ServiceEntity;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

/**
 * Cglib的AOP实现类
 * @author frost
 *
 */
public class CglibProxy implements MethodInterceptor {
	private Object target;
	private ServiceEntity entity;
	public Object bind(ServiceEntity entity, Object target) {
        this.target = target;
        this.entity = entity;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(this.target.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }
	
	@Override
	public Object intercept(Object obj, Method method, Object[] args,
			MethodProxy proxy) throws Throwable {
		// TODO Auto-generated method stub
		Object result = null;
		try {
			args = before(method, args);
			result = proxy.invokeSuper(obj, args);
			result = afterReturning(method, result);
		} catch (Exception e) {
			afterThrowing(e,method);
		}finally{
			afters(method);
		}
		
		return null;
	}
	
	private void afters(Method method) throws Exception {
		List <AopEntity> listAfter = entity.getAfter(method);
		for(int i=0;i<listAfter.size();i++){
			AopEntity entity = listAfter.get(i);
			IAfter iaf = (IAfter) entity.getObj();
			iaf.after();
		}
		
	}
	
	private Object[] before(Method method, Object[] args) throws Exception {
		List <AopEntity> listBefore = entity.getBefore(method);
		for(int i=0;i<listBefore.size();i++){
			AopEntity entity = listBefore.get(i);
			IBefore ib = (IBefore) entity.getObj();
			args = ib.before(args);
		}
		return args;
	}
	private Object afterReturning(Method method, Object result)
			throws Exception {
		List <AopEntity> listAfterReturn = entity.getAfterReturn(method);
		for(int i=0;i<listAfterReturn.size();i++){
			AopEntity entity = listAfterReturn.get(i);
			IAfterReturn iar =  (IAfterReturn) entity.getObj();
			result=iar.afterReturn(result);
		}
		return result;
	}
	
	private void afterThrowing(Exception e,Method method) throws Exception {
		List<AopEntity> listAfterThrow =entity.getAfterThrow(method);
		for(int i=0;i<listAfterThrow.size();i++){
			AopEntity entity = listAfterThrow.get(i);
			IAfterThrowing iat = (IAfterThrowing) entity.getObj();
			try {
				iat.afterThrow(e);
				e=null;
				continue;
			} catch (Exception e2) {
				e=e2;
			}
		}
		if(e!=null){
			throw new Exception(e);
		}
	}
}
